﻿/*
SINACOR - BMF&Bovespa
Arquivo: Importacao.cs
Criado em: 28-jun-2010 14:45:43
Arquiteto Responsável: p-wgeneroso
*/
using System;
using System.Collections.Generic;
using System.Text;
using Sinacor.Infra.Core.ProcessManager.Server;
using Sinacor.Infra.Common.Exceptions;
using Sinacor.Infra.Service.ExceptionHandling;
using PSE.ProcessManager.Common.Process;
using PSE.Framework.Communication.Adapters.File;
using PSE.Framework.Communication.Client.File.FlatFile;
using System.Threading;
using Sinacor.Infra.Service.Validation;
using PSE.ProcessManager.Server.Process.Security;
using Sinacor.Infra.Core.ProcessManager.Server.Security;
using PSE.Framework.Communication.Client.File.ExcelFile;

namespace Sinacor.Process.Bovespa.Alocacao.Server.ProcessLogic
{
    public class ImportacaoDistribuicaoNegocio : BaseProcessLogic
    {
        #region Atributos

        private ManualResetEvent _importFinishControl;
        private ExcelFileInputClient _client = null;
        private List<ProcessEntity.DistribuicaoNegocioDetail> _distribuicoes;
        private int _erroArquivoInvalido = 109798;
        private int _erroQuantidadeRegistrosInvalido = 109801;
        private Translator.LayoutToProcessEntity.DistribuicaoNegocio _translatorDistribuicao;
        private bool _erroLeituraArquivo = false;
        private int _recordCount;

        #endregion

        #region Eventos

        /// <summary>
        /// Evento disparado ao concluir uma importação de arquivo
        /// </summary>
        public event EventHandler ImportacaoIniciada;
        public event EventHandler<ProcessEventArgs<List<ProcessEntity.DistribuicaoNegocioDetail>>> ImportacaoConcluida;

        #endregion

        #region Construtor

        /// <summary>
        /// Construtor padrão
        /// </summary>
        public ImportacaoDistribuicaoNegocio()
        {
            _translatorDistribuicao = new Translator.LayoutToProcessEntity.DistribuicaoNegocio();
        }

        #endregion

        #region Propriedades

        public int ErroArquivoInvalido
        {
            get { return _erroArquivoInvalido; }
            set { _erroArquivoInvalido = value; }
        }

        public int ErroQuantidadeRegistrosInvalido
        {
            get { return _erroQuantidadeRegistrosInvalido; }
            set { _erroQuantidadeRegistrosInvalido = value; }
        }

        public bool ErroLeituraArquivo
        {
            get { return _erroLeituraArquivo; }
            set { _erroLeituraArquivo = value; }
        }

        #endregion

        #region EventHandler

        /// 
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void _client_FileClosed(object sender, FileClosedEventArgs e)
        {
            FecharClient();
        }

        /// 
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void _client_FileOpened(object sender, FileOpenedEventArgs e)
        {
            if (!IsAborted)
            {
                AtualizaStatus(5, "Bovespa.ImportacaoExportacao.Label.ValidandoArquivo");
                _recordCount = e.RecordCount;
                if (_recordCount <= 1)
                {
                    _erroLeituraArquivo = true;
                    this.HandleException(new BusinessException(ErroQuantidadeRegistrosInvalido), true);
                    FecharClient();
                    return;
                }

                if (_distribuicoes == null)
                    _distribuicoes = new List<ProcessEntity.DistribuicaoNegocioDetail>();
                _distribuicoes.Clear();
            }
        }

        /// 
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void _client_RecordRead(object sender, RecordEventArgs e)
        {
            try
            {
                if (IsAborted)
                {
                    _client.CancelFile();
                }
                else if (e.Record is Layout.DistribuicaoNegocioDetail)
                {
                    decimal porcentagem = ((_distribuicoes.Count * 90) / _recordCount) + 5;
                    AtualizaStatus(porcentagem, "Bovespa.ImportacaoExportacao.Label.LendoArquivo");

                    var distribuicao = _translatorDistribuicao.ToDistribuicaoNegocioDetail((Layout.DistribuicaoNegocioDetail)e.Record);
                    _distribuicoes.Add(distribuicao);
                }
            }
            catch (Exception ex)
            {
                _erroLeituraArquivo = true;

                this.HandleException(ex, true);

                FecharClient();
            }
        }

        /// 
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void _client_RecordReadError(object sender, RecordReadErrorEventArgs e)
        {
            _erroLeituraArquivo = true;

            this.HandleException(new BusinessException(ErroArquivoInvalido, e.Exception), true);

            FecharClient();
        }

        private void _client_FileCanceled(object sender, FileCanceledEventArgs e)
        {
            FecharClient();
        }

        #endregion

        #region Métodos Públicos

        public void ImportarDistribuicaoNegocio(ProcessEntity.Parameter.FiltroImportacaoDistribuicaoNegocio entity)
        {
            if (ImportacaoIniciada != null)
            {
                ImportacaoIniciada(this, new EventArgs());
            }

            if (!IsAborted
                && !_erroLeituraArquivo)
            {
                LerArquivoAlocacao(entity.NomeArquivo);
            }

            if (!IsAborted
                && !_erroLeituraArquivo)
            {
                AtualizaStatus(95, "Bovespa.ImportacaoExportacao.Label.FinalizandoProcessamento");

                if (ImportacaoConcluida != null)
                {
                    ImportacaoConcluida(this, new ProcessEventArgs<List<ProcessEntity.DistribuicaoNegocioDetail>>(_distribuicoes));
                }
            }
        }

        #endregion

        #region Métodos Privados

        private void LerArquivoAlocacao(string nomeArquivo)
        {
            _importFinishControl = new ManualResetEvent(false);

            _client = new ExcelFileInputClient();

            _client.Open("ImportacaoDistribuicaoNegocioExcel");

            _client.FileOpened += new EventHandler<FileOpenedEventArgs>(_client_FileOpened);
            _client.FileClosed += new EventHandler<FileClosedEventArgs>(_client_FileClosed);
            _client.RecordRead += new EventHandler<RecordEventArgs>(_client_RecordRead);
            _client.RecordReadError += new EventHandler<RecordReadErrorEventArgs>(_client_RecordReadError);
            _client.FileCanceled += new EventHandler<FileCanceledEventArgs>(_client_FileCanceled);

            _client.BeginImport(new FileReceiveParameter(System.IO.Path.GetFileName(nomeArquivo)));

            _importFinishControl.WaitOne();
        }

        private void FecharClient()
        {
            if (_client != null)
            {
                if (_client.Status == PSE.Framework.Communication.CommunicationStatus.Opened)
                {
                    _client.EndImport();
                    _client.Close();
                }

                _client = null;
            }

            if (_importFinishControl != null)
                _importFinishControl.Set();
        }

        private void AtualizaStatus(decimal progress, string resourceKey)
        {
            this.Status.Progress = Convert.ToInt32(Math.Round(progress, 0, MidpointRounding.ToEven));
            this.Status.Step = resourceKey;
            this.SendStatus();
        }

        #endregion
    }
}